/**
 * This file is part of Idegen, the application to create IDE project files.
 *
 * @copyright Copyright (c) 2011-2012, Walter Tamboer http://waltertamboer.nl
 * @file Idegen/Application/Settings.cpp
 */

#ifndef IDEGEN_APPLICATION_SETTINGS_HPP
#define IDEGEN_APPLICATION_SETTINGS_HPP

namespace Idegen
{
	enum GeneratorType;

	class IdegenGenerator;
	class IdegenProject;
	class IdegenProjectConfig;
	class IdegenSourceSet;
	
	typedef std::vector< IdegenGenerator* > IdegenGeneratorList;
	typedef std::vector< IdegenProject* > IdegenProjectList;
	typedef std::vector< IdegenSourceSet* > IdegenSourceSetList;

	struct SettingsScope
	{
		/** The project configuration that is actively parsed. */
		IdegenProjectConfig* Config;

		/** The generator that is actively parsed. */
		IdegenGenerator* Generator;
		
		/** The project that is actively parsed. */
		IdegenProject* Project;

		/** Initializes a new instance of this class. */
		SettingsScope() : Config( NULL ), Generator( NULL ), Project( NULL )
		{
		}
	};

	/** The settings of the instance that's running. */
	class Settings
	{
	public:
		/**
		 * Initializes a new instance of this class.
		 *
		 * @param[in] settingsFile The path to the settings file.
		 */
		Settings( const std::string& settingsFile );
		
		/**
		 * Initializes a new instance of this class.
		 *
		 * @param[in] settingsFile The path to the settings file.
		 * @param[in] basePath The base path used for the application to start working from.
		 */
		Settings( const std::string& settingsFile, const std::string& basePath );

		/** Cleans up all the resources used by this class. */
		~Settings();

		/**
		 * Finds the generator with the given name.
		 *
		 * @param[in] name The name of the generator to use.
		 * @return Returns an instance of the generator or NULL if the generator hasn't been found.
		 */
		IdegenGenerator* FindGenerator( const std::string& name ) const;

		/**
		 * Tries to find the project with the given name.
		 *
		 * @param[in] name The name of the project to find.
		 * @return Returns an instance of the project or NULL if the project hasn't been found.
		 */
		IdegenProject* FindProject( const std::string& name ) const;

		/**
		 * Gets the base path of the instance.
		 *
		 * @return Returns a string.
		 */
		std::string GetBasePath() const;

		/**
		 * Gets a list with all the generators.
		 *
		 * @returns Returns a GeneratorList type.
		 */
		IdegenGeneratorList GetGenerators() const;

		/**
		 * Gets the scope used for parsing.
		 *
		 * @return Returns the instance of SettingsScope.
		 */
		SettingsScope* GetScope();

		/**
		 * Parses all the includes in the level of the given parent and adds them to the parent node.
		 *
		 * @param[in] parent The parent to parse.
		 */
		void ParseIncludes( TiXmlElement* parent );

		/**
		 * Parses a new project by its name.
		 *
		 * @param[in] name The name of the project.
		 * @return Returns the project or NULL if it hasn't been parsed.
		 */
		IdegenProject* ParseProject( const std::string& name );

		/**
		 * Parses a new project by its TiXmlEelement.
		 *
		 * @param[in] parent The element to parse.
		 * @return Returns the project or NULL if it hasn't been parsed.
		 */
		IdegenProject* ParseProject( TiXmlElement* parent );

		/**
		 * Parses a new source set by its name.
		 *
		 * @param[in] name The name of the source set.
		 * @return Returns the source set or NULL if it hasn't been parsed.
		 */
		IdegenSourceSet* ParseSourceSet( const std::string& name );

		/**
		 * Parses a new source set by its name.
		 *
		 * @param[in] name The name of the source set.
		 * @param[in] parent The parent element to search in.
		 * @return Returns the source set or NULL if it hasn't been parsed.
		 */
		IdegenSourceSet* ParseSourceSet( const std::string& name, TiXmlElement* parent );

		/**
		 * Parses a new source set by its TiXmlEelement.
		 *
		 * @param[in] element The element to parse.
		 * @return Returns the source set or NULL if it hasn't been parsed.
		 */
		IdegenSourceSet* ParseSourceSet( TiXmlElement* element );

		/**
		 * Parses a variable and runs a function over its value.
		 *
		 * @param[in] begin The iterator.
		 * @param[in] end The ending iterator.
		 * @return Returns the result.
		 */
		std::string ParseVariableFunction( std::string::iterator& begin, std::string::iterator end );

		/**
		 * Parses a variable.
		 *
		 * @param[in] begin The iterator.
		 * @param[in] end The ending iterator.
		 * @return Returns the result.
		 */
		std::string ParseVariableName( std::string::iterator& begin, std::string::iterator end );

		/**
		 * Parses the variables within given value.
		 *
		 * @param[in] value The value to parse.
		 * @return Returns the parsed string.
		 */
		std::string ParseVariables( const std::string& value );

	private:
		/**
		 * Loads the settings.
		 *
		 * @param[in] path The path that contains the settings.
		 */
		void Load( const std::string& path );

		/**
		 * Parses a single generator that is defined in the config file.
		 *
		 * @param[in] parent The Xml element that should be parsed.
		 */
		void ParseGenerator( TiXmlElement* parent );

		/** A list with all the generators that exist. */
		IdegenGeneratorList m_Generators;

		/** A list with all the projects that exist. */
		IdegenProjectList m_Projects;

		/** A list with all the sources that exist. */
		IdegenSourceSetList m_Sources;

		/** The root element of the settings file. */
		TiXmlElement* m_RootElement;

		/** The base path of the application. */
		std::string m_BasePath;

		/** The scope used to parse. */
		SettingsScope m_Scope;
	};

	/**
	 * Parses a string attribute with the given name.
	 *
	 * @param[in] element The element to search the attribute in.
	 * @param[in] name The name of the attribute.
	 * @param[out] value A reference to store the value.
	 * @return Returns true when the attribute was found; false otherwise.
	 */
	bool ParseAttributeString( TiXmlElement* element, const std::string& name, std::string& value );

	/**
	 * Parses an integer attribute with the given name.
	 *
	 * @param[in] element The element to search the attribute in.
	 * @param[in] name The name of the attribute.
	 * @param[out] value A reference to store the value.
	 * @return Returns true when the attribute was found; false otherwise.
	 */
	bool ParseAttributeInt( TiXmlElement* element, const std::string& name, int& value );

	/**
	 * Parses a boolean value within an element.
	 *
	 * @param[in] element The element to read.
	 * @param[out] value The value to store the result in.
	 * @return Returns true when the element has been parsed; false otherwise.
	 */
	bool ParseElementBoolean( TiXmlElement* element, bool& value );

	/**
	 * Parses a floating point value within an element.
	 *
	 * @param[in] element The element to read.
	 * @param[out] value The value to store the result in.
	 * @return Returns true when the element has been parsed; false otherwise.
	 */
	bool ParseElementFloat( TiXmlElement* element, float& value );
	
	/**
	 * Parses a integer value within an element.
	 *
	 * @param[in] element The element to read.
	 * @param[out] value The value to store the result in.
	 * @return Returns true when the element has been parsed; false otherwise.
	 */
	bool ParseElementInt( TiXmlElement* element, int& value );
	
	/**
	 * Parses a string value within an element.
	 *
	 * @param[in] element The element to read.
	 * @param[out] value The value to store the result in.
	 * @return Returns true when the element has been parsed; false otherwise.
	 */
	bool ParseElementString( TiXmlElement* element, std::string& value );
}

#endif
